/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
define(["require", "exports", "path", "./features/bufferSyncSupport", "./features/formattingConfigurationManager", "./utils/languageConfigurations", "./features/diagnostics", "./utils/fileSchemes", "./features/baseCodeLensProvider"], function (require, exports, path_1, bufferSyncSupport_1, formattingConfigurationManager_1, languageConfigurations, diagnostics_1, fileSchemes, baseCodeLensProvider_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const validateSetting = 'validate.enable';
    class LanguageProvider {
        constructor(client, description, commandManager, typingsStatus, vscode) {
            this.client = client;
            this.description = description;
            this.vscode = vscode;
            this.toUpdateOnConfigurationChanged = [];
            this._validate = true;
            this.disposables = [];
            this.versionDependentDisposables = [];
            this._documentSelector = null;
            this.formattingOptionsManager = new formattingConfigurationManager_1.default(client, vscode);
            this.bufferSyncSupport = new bufferSyncSupport_1.default(client, description.modeIds, {
                delete: (file) => {
                    this.diagnosticsManager.delete(file);
                }
            }, this._validate, vscode);
            this.diagnosticsManager = new diagnostics_1.default(description.id, this.client, vscode);
            vscode.workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables);
            this.configurationChanged();
            client.onReady(() => __awaiter(this, void 0, void 0, function* () {
                yield this.registerProviders(client, commandManager, typingsStatus);
                this.bufferSyncSupport.listen();
            }));
        }
        dispose() {
            while (this.disposables.length) {
                const obj = this.disposables.pop();
                if (obj) {
                    obj.dispose();
                }
            }
            while (this.versionDependentDisposables.length) {
                const obj = this.versionDependentDisposables.pop();
                if (obj) {
                    obj.dispose();
                }
            }
            this.diagnosticsManager.dispose();
            this.bufferSyncSupport.dispose();
            this.formattingOptionsManager.dispose();
        }
        get documentSelector() {
            if (!this._documentSelector) {
                this._documentSelector = [];
                for (const language of this.description.modeIds) {
                    for (const scheme of fileSchemes.supportedSchemes) {
                        this._documentSelector.push({ language, scheme });
                    }
                }
            }
            return this._documentSelector;
        }
        registerProviders(client, commandManager, typingsStatus) {
            return __awaiter(this, void 0, void 0, function* () {
                const selector = this.documentSelector;
                const config = this.vscode.workspace.getConfiguration(this.id);
                this.disposables.push(this.vscode.languages.registerCompletionItemProvider(selector, new (yield new Promise((resolve_1, reject_1) => { require(['./features/completionItemProvider'], resolve_1, reject_1); })).default(client, typingsStatus, commandManager, this.vscode), '.', '"', '\'', '/', '@'));
                this.disposables.push(this.vscode.languages.registerCompletionItemProvider(selector, new (yield new Promise((resolve_2, reject_2) => { require(['./features/directiveCommentCompletionProvider'], resolve_2, reject_2); })).default(client, this.vscode), '@'));
                const { TypeScriptFormattingProvider, FormattingProviderManager } = yield new Promise((resolve_3, reject_3) => { require(['./features/formattingProvider'], resolve_3, reject_3); });
                const formattingProvider = new TypeScriptFormattingProvider(client, this.formattingOptionsManager, this.vscode);
                formattingProvider.updateConfiguration(config);
                this.disposables.push(this.vscode.languages.registerOnTypeFormattingEditProvider(selector, formattingProvider, ';', '}', '\n'));
                const formattingProviderManager = new FormattingProviderManager(this.description.id, formattingProvider, selector, this.vscode);
                formattingProviderManager.updateConfiguration();
                this.disposables.push(formattingProviderManager);
                this.toUpdateOnConfigurationChanged.push(formattingProviderManager);
                this.disposables.push(this.vscode.languages.registerCompletionItemProvider(selector, new (yield new Promise((resolve_4, reject_4) => { require(['./features/jsDocCompletionProvider'], resolve_4, reject_4); })).default(client, commandManager, this.vscode), '*'));
                this.disposables.push(this.vscode.languages.registerHoverProvider(selector, new (yield new Promise((resolve_5, reject_5) => { require(['./features/hoverProvider'], resolve_5, reject_5); })).default(client, this.vscode)));
                this.disposables.push(this.vscode.languages.registerDefinitionProvider(selector, new (yield new Promise((resolve_6, reject_6) => { require(['./features/definitionProvider'], resolve_6, reject_6); })).default(client, this.vscode)));
                this.disposables.push(this.vscode.languages.registerDocumentHighlightProvider(selector, new (yield new Promise((resolve_7, reject_7) => { require(['./features/documentHighlightProvider'], resolve_7, reject_7); })).default(client, this.vscode)));
                this.disposables.push(this.vscode.languages.registerReferenceProvider(selector, new (yield new Promise((resolve_8, reject_8) => { require(['./features/referenceProvider'], resolve_8, reject_8); })).default(client, this.vscode)));
                this.disposables.push(this.vscode.languages.registerDocumentSymbolProvider(selector, new (yield new Promise((resolve_9, reject_9) => { require(['./features/documentSymbolProvider'], resolve_9, reject_9); })).default(client, this.vscode)));
                this.disposables.push(this.vscode.languages.registerSignatureHelpProvider(selector, new (yield new Promise((resolve_10, reject_10) => { require(['./features/signatureHelpProvider'], resolve_10, reject_10); })).default(client, this.vscode), '(', ','));
                this.disposables.push(this.vscode.languages.registerRenameProvider(selector, new (yield new Promise((resolve_11, reject_11) => { require(['./features/renameProvider'], resolve_11, reject_11); })).default(client, this.vscode)));
                this.disposables.push(this.vscode.languages.registerCodeActionsProvider(selector, new (yield new Promise((resolve_12, reject_12) => { require(['./features/quickFixProvider'], resolve_12, reject_12); })).default(client, this.formattingOptionsManager, commandManager, this.diagnosticsManager, this.vscode)));
                this.disposables.push(this.vscode.languages.registerCodeActionsProvider(selector, new (yield new Promise((resolve_13, reject_13) => { require(['./features/refactorProvider'], resolve_13, reject_13); })).default(client, this.formattingOptionsManager, commandManager, this.vscode)));
                this.registerVersionDependentProviders();
                const cachedResponse = new baseCodeLensProvider_1.CachedNavTreeResponse();
                const referenceCodeLensProvider = new (yield new Promise((resolve_14, reject_14) => { require(['./features/referencesCodeLensProvider'], resolve_14, reject_14); })).default(client, this.description.id, cachedResponse, this.vscode);
                referenceCodeLensProvider.updateConfiguration();
                this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider);
                this.disposables.push(this.vscode.languages.registerCodeLensProvider(selector, referenceCodeLensProvider));
                const implementationCodeLensProvider = new (yield new Promise((resolve_15, reject_15) => { require(['./features/implementationsCodeLensProvider'], resolve_15, reject_15); })).default(client, this.description.id, cachedResponse, this.vscode);
                implementationCodeLensProvider.updateConfiguration();
                this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider);
                this.disposables.push(this.vscode.languages.registerCodeLensProvider(selector, implementationCodeLensProvider));
                this.disposables.push(this.vscode.languages.registerWorkspaceSymbolProvider(new (yield new Promise((resolve_16, reject_16) => { require(['./features/workspaceSymbolProvider'], resolve_16, reject_16); })).default(client, this.description.modeIds, this.vscode)));
                if (!this.description.isExternal) {
                    for (const modeId of this.description.modeIds) {
                        this.disposables.push(this.vscode.languages.setLanguageConfiguration(modeId, languageConfigurations.jsTsLanguageConfiguration));
                    }
                }
            });
        }
        configurationChanged() {
            const config = this.vscode.workspace.getConfiguration(this.id);
            this.updateValidate(config.get(validateSetting, true));
            for (const toUpdate of this.toUpdateOnConfigurationChanged) {
                toUpdate.updateConfiguration();
            }
        }
        handles(file, doc) {
            if (doc && this.description.modeIds.indexOf(doc.languageId) >= 0) {
                return true;
            }
            if (this.bufferSyncSupport.handles(file)) {
                return true;
            }
            const base = path_1.basename(file);
            return !!base && base === this.description.configFile;
        }
        get id() {
            return this.description.id;
        }
        get diagnosticSource() {
            return this.description.diagnosticSource;
        }
        updateValidate(value) {
            if (this._validate === value) {
                return;
            }
            this._validate = value;
            this.bufferSyncSupport.validate = value;
            this.diagnosticsManager.validate = value;
            if (value) {
                this.triggerAllDiagnostics();
            }
        }
        reInitialize() {
            this.diagnosticsManager.reInitialize();
            this.bufferSyncSupport.reOpenDocuments();
            this.bufferSyncSupport.requestAllDiagnostics();
            this.formattingOptionsManager.reset();
            this.registerVersionDependentProviders();
        }
        registerVersionDependentProviders() {
            return __awaiter(this, void 0, void 0, function* () {
                while (this.versionDependentDisposables.length) {
                    const obj = this.versionDependentDisposables.pop();
                    if (obj) {
                        obj.dispose();
                    }
                }
                if (!this.client) {
                    return;
                }
                const selector = this.documentSelector;
                if (this.client.apiVersion.has220Features()) {
                    this.versionDependentDisposables.push(this.vscode.languages.registerImplementationProvider(selector, new (yield new Promise((resolve_17, reject_17) => { require(['./features/implementationProvider'], resolve_17, reject_17); })).default(this.client, this.vscode)));
                }
                if (this.client.apiVersion.has213Features()) {
                    this.versionDependentDisposables.push(this.vscode.languages.registerTypeDefinitionProvider(selector, new (yield new Promise((resolve_18, reject_18) => { require(['./features/typeDefinitionProvider'], resolve_18, reject_18); })).default(this.client, this.vscode)));
                }
            });
        }
        triggerAllDiagnostics() {
            this.bufferSyncSupport.requestAllDiagnostics();
        }
        syntaxDiagnosticsReceived(file, syntaxDiagnostics) {
            this.diagnosticsManager.syntaxDiagnosticsReceived(file, syntaxDiagnostics);
        }
        semanticDiagnosticsReceived(file, semanticDiagnostics) {
            this.diagnosticsManager.semanticDiagnosticsReceived(file, semanticDiagnostics);
        }
        configFileDiagnosticsReceived(file, diagnostics) {
            this.diagnosticsManager.configFileDiagnosticsReceived(file, diagnostics);
        }
    }
    exports.default = LanguageProvider;
});
